/*
                       _oo0oo_
                      o8888888o
                      88" . "88
                      (| -_- |)
                      0\  =  /0
                    ___/`---'\___
                  .' \\|     |-- '.
                 / \\|||  :  |||-- \
                / _||||| -:- |||||- \
               |   | \\\  -  --/ |   |
               | \_|  ''\---/''  |_/ |
               \  .-\__  '-'  ___/-. /
             ___'. .'  /--.--\  `. .'___
          ."" '<  `.___\_<|>_/___.' >' "".
         | | :  `- \`.;`\ _ /`;.`/ - ` : | |
         \  \ `_.   \_ __\ /__ _/   .-` /  /
     =====`-.____`.___ \_____/___.-`___.-'=====
                       `=---='


     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

               佛祖保佑         永无BUG

 Made by Alex @7/1/2017 9:49 AM

*/
package core

import (
	"database/sql"

	"strings"

	"bytes"

	_ "github.com/go-sql-driver/mysql"
	"github.com/huandu/xstrings"
	"github.com/picago/model-generator/xerrros"
)

type Field struct {
	Name    string
	Type    string
	Comment string
}

func GetTable(dataSource string, table string) (fields []Field) {
	db, err := sql.Open("mysql", dataSource)
	xerrros.PanicIfError(err)
	defer db.Close()
	query := `SELECT a.COLUMN_NAME,a.DATA_TYPE, a.COLUMN_COMMENT
		FROM  information_schema.COLUMNS a
		WHERE a.TABLE_NAME = ?`
	rows, err := db.Query(query, table)
	xerrros.PanicIfError(err)
	tokenizer := NewTokenizer()
	for rows.Next() {
		var field Field
		rows.Scan(&field.Name, &field.Type, &field.Comment)
		field.Name = tokenizer.ToJavaName(field.Name)
		fields = append(fields, field)
	}
	return
}

type Config struct {
	Host string `required:"true"`
	Package string `required:"true"`
	Tables []string `required:"true"`
}

func GenJava(dataSource string, table string, packageName string) string {
	fields := GetTable(dataSource, table)
	var fieldBuf bytes.Buffer
	var importBuf bytes.Buffer
	importSet := make(map[string]struct{}, 4)
	var terBuf bytes.Buffer
	// 第一行
	copyright := `/**
 * Copyright(c) Foresee Science & Technology Ltd.
 */` + "\n"
	importBuf.WriteString(copyright)
	importBuf.WriteString("package " + packageName + ";\n\n")
	class := xstrings.ToCamelCase(table)
	fieldBuf.WriteString("\npublic class " + class + " {\n\n")
	for _, field := range fields {
		_type := findType(field.Type)
		if strings.Contains(_type, ".") {
			_type = handleDotType(importSet, _type, &importBuf)
		}

		if field.Comment != "" {
			comment := `    /** ` + field.Comment + "*/\n"
			fieldBuf.WriteString(comment)
		}
		fieldBuf.WriteString("    private " + _type + " " + field.Name + ";\n")
		handleTer(field, _type, &terBuf)
	}
	importBuf.WriteString(fieldBuf.String())
	importBuf.WriteString(terBuf.String())
	importBuf.WriteString("}")
	return importBuf.String()
}
func handleTer(field Field, _type string, buffer *bytes.Buffer) {
	setter := "\n    public void set" + xstrings.FirstRuneToUpper(field.Name) + "(" + _type + " " + field.Name + ") {\n"
	setter = setter + `        this.` + field.Name + " = " + field.Name + ";\n    }\n"
	buffer.WriteString(setter)
	getter := "\n    public " + _type + " get" + xstrings.FirstRuneToUpper(field.Name) + "() {\n"
	getter = getter + `        return this.` + field.Name + ";\n" + "    }\n"
	buffer.WriteString(getter)
}

func handleDotType(importSet map[string]struct{}, _type string, importBuf *bytes.Buffer) string {
	_, ok := importSet[_type]
	if !ok {
		importSet[_type] = struct{}{}
		importBuf.WriteString("import " + _type + ";\n")
	}
	pkgs := strings.Split(_type, ".")
	// 包名
	_type = pkgs[len(pkgs)-1]
	return _type
}

func findType(dbType string) string {
	if strings.Contains(dbType, "char") || strings.Contains(dbType, "text") {
		return "String"
	} else if strings.Contains(dbType, "decimal") {
		return "double"
	} else if strings.Contains(dbType, "float") {
		return "float"
	} else if strings.Contains(dbType, "bigint") {
		return "long"
	} else if strings.Contains(dbType, "int") {
		return "int"
	} else if strings.Contains(dbType, "blob") || strings.Contains(dbType, "binary") {
		return "byte[]"
	} else if strings.Contains(dbType, "datetime") || strings.Contains(dbType, "timestamp") {
		return "java.util.Date"
	}
	panic("没有这样的类型: " + dbType)
}
